#include "sphere.h"



/* alpha est un angle en radiant */
/* definissant la netteté des cercles */
void drawCircle (Point c,double alpha, double r)
{
  int i;
  for (i=0;i<360;i++)
    {
      /* cercle des x par rapport aux y */
      Point tmp1=pt(c.x+cos(alpha*i)*r,c.y+sin(alpha*i)*r,c.z);
      drawTruePoint(tmp1);
      /* cercle des x par rapport aux z */
      Point tmp2=pt(c.x+cos(alpha*i)*r,c.y,c.z+sin(alpha*i)*r);
      drawTruePoint(tmp2);
      /* cercle des y par rapport aux z */
      /* (facultatif) */
      Point tmp3=pt(c.x,c.y+cos(alpha*i)*r,c.z+sin(alpha*i)*r);
      drawTruePoint(tmp3);
    }
  return;
}

void testDrawSphere (Point c,double alpha,double r)
{
  int i;
  double perfect=PI/180.;

  /* compteur a mettre en radiant ?! */
  for (i=0;i<360;i++)
    {
      Point tmp2=pt(c.x+cos(perfect*i)*r,c.y,c.z+sin(perfect*i)*r);
      drawTruePoint(tmp2);
    }
  for (i=0;i<360;i++)
    {
      Point tmp2=pt(c.x+cos(perfect*i)*r,c.y+sin(i*PI/180)*sin(alpha),c.z+sin(perfect*i)*cos(alpha)*r);
      drawTruePoint(tmp2);
    }
  return;
}

void drawSphereHori (Point c,double alpha,double r)
{
  int i,j;
  double perfect=PI/180.;

  /* cercle des x par rapport aux z */
  /* compteur a mettre en radiant ?! */
  for (j=0;j<360;j++)
    for (i=0;i<360;i++)
      {
	Point tmp2=pt(c.x+cos(perfect*i)*r, c.y+sin(i*PI/180)*sin(alpha*j), c.z+sin(perfect*i)*cos(alpha*j)*r);
	drawTruePoint(tmp2);
      }
  return;
}

void drawSphereVerti (Point c,double alpha,double r)
{
  int i,j;
  double perfect=PI/180.;

  /* compteur a mettre en radiant ?! */
  for (j=0;j<360;j++)
    for (i=0;i<360;i++)
      {
	/* cercle des y par rapport aux z */
	/* (facultatif) */
	Point tmp3=pt(c.x+sin(rad(i)*PI/180)*sin(alpha*rad(j)),c.y+cos(perfect*rad(i))*r,c.z+sin(perfect*rad(i))*cos(alpha*rad(j))*r);
	drawTruePoint(tmp3);

      }
  return;
}

/*----------------------- produit scalaire 2d */
/*---------------- avec les angles */


/* /\* problème: beta n'est pas pondéré *\/ */
/* /\* renvoie la couleur calculée *\/ */
/* Couleur couleur_axe(double rayon,double alpha,double beta,int nbcoup,double SALPHA,double SBETA) */
/* { */
/*   double angleBeta=180-SBETA+beta; */
/*   double coeffBeta=rayon*cos(rad(angleBeta)); */

/*   double angleAlpha=180-SALPHA+alpha; */
/*   double coeffAlpha=rayon*cos(rad(angleAlpha)); */

/* /\* compri entre -R Et +R *\/ */
/*   coeffAlpha+=rayon; */
/*   coeffBeta+=rayon; */
/*   coeffAlpha/=(2*rayon); */
/*   coeffBeta/=(2*rayon); */
/*   /\* pour avoir des valeurs positives entre 0 et 1 *\/ */

/*   /\* NON OPTIMAL: *\/ */
/* /\* /\\* si l'axe est vertical, on ne prend pas en compte *\\/ *\/ */
/* /\* /\\* l'angle alpha mais seulement l'angle beta *\\/ *\/ */
/* /\*   if ((SBETA>89.)||(SBETA<-89.)) { *\/ */
/* /\*     coeffAlpha=0; *\/ */
/* /\*     coeffBeta*=2.; *\/ */
/* /\*   } *\/ */

/*  /\* OPTIMAL: une ponderation dans le calcul de la moyenne *\/ */
/*   double ponderAlpha=-1./90.*fabs(SBETA)+1; */
/*   /\* moyenne pondéré *\/ */
/*   double coeffMiddle=(ponderAlpha*coeffAlpha+coeffBeta) */
/*     /(1+ponderAlpha); */

/*   /\* /\\* premier test d'affichage: utiliser 2 composantes diff *\\/ *\/ */
/*   /\* chooseColor(1.-coeffAlpha,1-coeffBeta,0.); *\/ */

/*   /\* deuxieme test prendre la moyenne des coeff *\/ */
/*   chooseColor(1.-coeffMiddle,0.,0.); */

/*   /\* /\\* troisieme test: les 2 coeffs et la moyenne *\\/ *\/ */
/*   /\* chooseColor(1-coeffAlpha,1-coeffBeta,1-coeffMiddle); *\/ */

/*   /\* /\\* quatrieme test: la moyenne sur tous les axes *\\/ *\/ */
/*   /\* chooseColor(1-coeffMiddle,1-coeffMiddle,1-coeffMiddle); *\/ */

/*   return cl(1.-coeffMiddle,0.,0.); */
/* } */

/*----------------------- produit scalaire 3d */
Couleur couleur_axe(double R,Point surSphere,Point mouvant)
{
  Point normal=normalise(mouvant);
  double scal=scalaire(surSphere,normal);
  /* comprit entre -R et R */
  scal+=R;
  scal/=(2.*R);
  /* comprit entre 0 et 1 */
  chooseColor(scal,0.,0.);
  return cl(scal,0.,0.);
}


void drawSphere (Point c,double R, int nbcoup,Point SPMOVE)
{
  double x,y,z;
  double alpha=0.;
  double beta=-90.;
  double r;

  double pasAlpha=360./(double)nbcoup;
  double pasBeta=180./(double)nbcoup;

  Point vectorMove=toVector(SPMOVE,c);
  Point vectorSurSphere;
  int i,j;
  for (i=0;i<nbcoup+1;i++)
    {
      /* le rayon du sous cercle */
      r=R*cos(rad(beta));
      /* le sous cercle qu'on trace */
      z=c.z+sin(rad(beta))*R;
      
      for (j=0;j<nbcoup+1;j++)
	{
	  /* cercle des x par rapport aux y */
	  x=c.x+cos(rad(alpha))*r;
	  y=c.y+sin(rad(alpha))*r;

	  vectorSurSphere=toVector(pt(x,y,z),c);
	  couleur_axe(R,vectorSurSphere,vectorMove); /* le reste est global */
	  drawPoint(x,y,z);
	  alpha+=pasAlpha;
	}
      beta+=pasBeta;
    }
  return;
}
  /* double angle=180-i*SPASBeta; */





/* nbcoup nombre de coupe */
void drawQuadSphere (Point c,double R, int nbcoup,Point SPMOVE)
{
  Point vectorMove=toVector(SPMOVE,c);
  Point vectorSurSphere;

  double x,y,z;
  double alpha=0.;
  double beta=-90.;
  double r;
  Point p1,p2,p3,p4;

  double pasAlpha=360./(double)nbcoup;
  double pasBeta=180./(double)nbcoup;

  Point** matrice=newMatricePoint(nbcoup+1);
  /* booleen: est-ce le premier tour  */

  int i,j;
  for (i=0;i<nbcoup+1;i++)
    {
      /* le rayon du sous cercle */
      r=R*cos(rad(beta));
      /* le sous cercle qu'on trace */
      z=c.z+sin(rad(beta))*R;

      for (j=0;j<nbcoup+1;j++)
	{
	  /* cercle des x par rapport aux y */
	  x=c.x+cos(rad(alpha))*r;
	  y=c.y+sin(rad(alpha))*r;
	  alpha+=pasAlpha;

	  matrice[i][j]=pt(x,y,z);
	  vectorSurSphere=toVector(pt(x,y,z),c);

	  couleur_axe(R,vectorSurSphere,vectorMove); /* le reste est global */
	  /* si ce n'est pas le premier tour, on dessine des quad */
	  if (i!=0)
	    {
	      if (j>0)
		{
		  p1=matrice[i-1][j];
		  p2=matrice[i-1][j-1];
		  p3=matrice[i][j-1];
		  p4=matrice[i][j];
		  drawQuad(p1,p2,p3,p4);
		}
	    }
	}
      alpha=0.;
      beta+=pasBeta;
    }
  free(matrice);
  return;
}
/* les angles pour avoir un point:*/
/* beta=i*pasBeta */
/* alpha=j*pasAlpha */

/* nbcoup nombre de coupe */
void testDrawQuadSphere (Point c,double R, int nbcoup,Point SPMOVE)
{
  Point vectorMove=toVector(SPMOVE,c);
  Point vectorSurSphere;

  double x,y,z;
  double alpha=0.;
  double beta=-90.;
  double r;
  Point p1,p2,p3,p4;

  double pasAlpha=360./(double)nbcoup;
  double pasBeta=180./(double)nbcoup;

  Point** matrice=newMatricePoint(nbcoup+1);
  Couleur** color=newMatriceCouleur(nbcoup+1);


  int i,j;
  for (i=0;i<nbcoup+1;i++)
    {
      /* le rayon du sous cercle */
      r=R*cos(rad(beta));
      /* le sous cercle qu'on trace */
      z=c.z+sin(rad(beta))*R;

      
      for (j=0;j<nbcoup+1;j++)
	{
	  /* cercle des x par rapport aux y */
	  x=c.x+cos(rad(alpha))*r;
	  y=c.y+sin(rad(alpha))*r;
	  alpha+=pasAlpha;

	  matrice[i][j]=pt(x,y,z);
	  vectorSurSphere=toVector(pt(x,y,z),c);
	  color[i][j]=couleur_axe(R,vectorSurSphere,vectorMove);

	  /* si ce n'est pas le premier tour, on dessine des quad */
	  if (i!=0)
	    {
	      if (j>0)
		{
		  glBegin(GL_QUADS);
		  chooseCouleur(color[i-1][j]);
		  /* printf("color:%f\n",color[i-1][j].R); */
		  p1=matrice[i-1][j];
		  glVertex3f(p1.x,p1.y,p1.z);

		  chooseCouleur(color[i-1][j-1]);
		  p2=matrice[i-1][j-1];
		  glVertex3f(p2.x,p2.y,p2.z);

		  chooseCouleur(color[i][j-1]);
		  p3=matrice[i][j-1];
		  glVertex3f(p3.x,p3.y,p3.z);

		  chooseCouleur(color[i][j]);
		  p4=matrice[i][j];
		  glVertex3f(p4.x,p4.y,p4.z);
		  glEnd();
		}
	    }
	}
      alpha=0.;
      beta+=pasBeta;
    }
  libererMatricePoint(matrice,nbcoup+1);
  libererMatriceCouleur(color,nbcoup+1);
  return;
}

void set_move(Point c,int nbcoup,Point SPMOVE,
	      double* SPASAlpha,double* SPASBeta,
	      unsigned char boolDrawMove)
{
  /* on place le point au dessus de la sphere */

  *SPASAlpha=360./(double)nbcoup;
  *SPASBeta=180./(double)nbcoup;

/* on trace le point mouvant en dehors du cercle */
/* avec son segment qui le relie au centre du cercle */
  chooseColorOpaque(0.,1.,0.);
  if (boolDrawMove)
    {
      glPointSize(5.0);
      drawTruePoint(SPMOVE);
      drawTrueLine(SPMOVE,c);
      drawTrueLine(SPMOVE,pt((SPMOVE).x,(SPMOVE).y,0));
    }
  chooseColorOpaque(0.,0.,1.);
  glPointSize(10.0);
  drawTruePoint(c);
  glPointSize(1.0);


  return ;
}

/* 0<rayon<=10 */
double random_rayon()
{
  double ret=((double)rand()+1.)/(double)RAND_MAX;
  return (ret*(double)4.);
}

/* 10<y<=99 */
/* -(y+3)/2<=x<=(y+3)/2 */
/* -(y+3)<=z<=(y+3) */
Point random_centre()
{
  double x,y,z;
  y=((double)rand()+1.)/(double)RAND_MAX;
  x=((double)rand())/(double)RAND_MAX;
  z=((double)rand())/(double)RAND_MAX;
  y*=89.+10;

  x-=0.5;
  z-=0.5;

  x*=(y+3)*2;
  z*=(y+3)*2;
  return pt(x,y,z);
}

/* 0<nbcoup<=20 */
int random_coupes()
{
  int ret=(rand()%19)+1;
  return ret;
}


/* if nbcoup==0 choose a random nbcoup */
void stressTest (int nbsphere,int nbcoup,Point SPMOVE)
{
  srand(time(NULL));
  int i;
  double rayon=0.;
  Point centre;
  int* pointer_real_coupes=&nbcoup;
  int local_random_coupes=0;
  /* si nbcoup vaut 0 on utilise un random */
  if (nbcoup==0)
    pointer_real_coupes=&local_random_coupes;
  for (i=0;i<nbsphere;i++)
    {
      rayon=random_rayon();
      centre=random_centre();
      local_random_coupes=random_coupes();
      testDrawQuadSphere(centre,rayon,*pointer_real_coupes,SPMOVE);
    }
  return;
}










